package com.example.service.impl;

import com.example.dao.HotPositionDao;
import com.example.service.IHotPositionService;
import com.example.vo.HotPosition;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author BeauFang
 * Date: 2020/8/1
 */
@Service
public class HotPositionServiceImpl implements IHotPositionService {

    private final String LOCK_HOT_POSITION = "lock:hot-position";
    @Autowired
    private RedisService redisService;

    @Autowired
    private HotPositionDao hotPositionDao;

    @Autowired
    private GuavaCacheService guavaCacheService;

    @Autowired
    private Redisson redisson;

    /**
     * 首先从 Redis 缓存中查询数据，如果 Redis 缓存为空，通过分布式锁限制只允许一个线程到数据库里查询数据。
     * 并将查询到的数据更新到 Redis 和 Guava 缓存。
     * 其他的线程直接读取 Guava 缓存中的数据。
     *
     * @return 热门职位
     */
    @Override
    public List<HotPosition> findAllHotPosition() {
        List<HotPosition> hotPosition = redisService.getHotPosition();
        if (hotPosition != null && hotPosition.size() > 0) {
            System.out.println("直接从 Redis 缓存中加载数据");
            return hotPosition;
        }
        System.out.println("Redis 缓存数据为空 ");
        RLock lock = redisson.getLock(LOCK_HOT_POSITION);
        boolean canLock = false;
        try {
            canLock = lock.tryLock(100L, TimeUnit.MILLISECONDS);
            if (canLock) {
                // 获取锁成功
                // 模拟耗时操作，测试从本地 guava 缓存中读取数据
                Thread.sleep(1000L);
                System.out.println("休眠 1000L 完成");
                // 从数据库获取数据
                List<HotPosition> hotPositionList = hotPositionDao.findAll();
                // 更新 redis 缓存
                redisService.setHotPosition(hotPositionList);
                // 更新本地缓存
                guavaCacheService.loadHotPosition();
                System.out.println("从数据库获取数据，并写入缓存成功");
                return hotPositionList;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 如果时当前线程锁住，需要解锁
            if (canLock) {
                lock.unlock();
            }
        }
        // 如果获取锁失败（超时）, 直接从本地缓存取
        System.out.println("从本地 guava 缓存中读取数据");
        return guavaCacheService.getHotPositions();
    }
}
